package com.gonsin.gmessage.logic.proxy;

import com.gonsin.gmessage.annotations.GMessageEnvironment;
import com.gonsin.gmessage.annotations.GMessageReceiver;
import com.gonsin.gmessage.logic.GMessage;
import com.gonsin.gmessage.logic.GMessageScan;
import com.gonsin.gmessage.logic.mqtt.MqttClientManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.annotation.JmsListeners;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerEndpointRegistry;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.*;

@Slf4j
public class GMessageInitRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {


    private final Map<TypeFilter, ImportBeanDefinitionRegistrar> senderRegistrars = new HashMap<TypeFilter, ImportBeanDefinitionRegistrar>();

    private ResourceLoader resourceLoader;

    private Environment environment;

    public GMessageInitRegister(){
        this.senderRegistrars.put(new AnnotationTypeFilter(GMessage.class, true), new GMessageRegister());
    }


    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        if(GMessageEnvironment.LOG){
            log.info("GMessageInitRegister 开始注入 @GMessage ");
        }

        Collection<String> basePackages = getBasePackages(importingClassMetadata, registry);

        ClassPathScanningCandidateComponentProvider scanner =
                new ClassPathScanningCandidateComponentProvider(false, this.environment) {

                    @Override
                    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                        return beanDefinition.getMetadata().isIndependent()
                                && !beanDefinition.getMetadata().isAnnotation();
                    }

                };

        for (TypeFilter typeFilter : this.senderRegistrars.keySet()) {
            scanner.addIncludeFilter(typeFilter);
        }

        scanner.setResourceLoader(this.resourceLoader);

        // 创建MqttClientManager，用于连接到artemis
        GenericBeanDefinition mqttClientManagerDefinition = new GenericBeanDefinition();
        mqttClientManagerDefinition.setBeanClass(MqttClientManager.class);
        registry.registerBeanDefinition("mqttClientManager", mqttClientManagerDefinition);


        // 扫描GMessage的批注，创建对应的代理类
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    for (ImportBeanDefinitionRegistrar registrar : this.senderRegistrars.values()) {
                        registrar.registerBeanDefinitions(((AnnotatedBeanDefinition) candidateComponent).getMetadata(),
                                registry);
                    }
                }
            }
        }
    }


    protected Collection<String> getBasePackages(AnnotationMetadata importingClassMetadata,
                                                 BeanDefinitionRegistry registry) {
        Map<String, Object> componentScan =
                importingClassMetadata.getAnnotationAttributes(GMessageScan.class.getName());
//        Map<String, Object> componentScan =
//                importingClassMetadata.getAnnotationAttributes(EnableGMessage.class.getName());

        Set<String> basePackages = new HashSet<>();

        for (String pkg : (String[]) componentScan.get("value")) { // NOSONAR - never null
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        if(CollectionUtils.isEmpty(basePackages)){
            String packageName = importingClassMetadata.getClassName();
            packageName = packageName.substring(0, packageName.lastIndexOf("."));
            basePackages.add(packageName);
        }

        return basePackages;
    }


//    public BeanDefinitionHolder parse(Map<String, Object> gatewayAttributes) {
//
//        BeanDefinitionBuilder gatewayProxyBuilder =
//                BeanDefinitionBuilder.genericBeanDefinition(GMessageProxyFactoryBean.class);
//
//        String serviceInterface = (String) gatewayAttributes.get("serviceInterface");
//        if (!StringUtils.hasText(serviceInterface)) {
//            serviceInterface = "org.springframework.integration.gateway.RequestReplyExchanger";
//        }
//        String id = (String) gatewayAttributes.get("name");
//        if (!StringUtils.hasText(id)) {
//            id = Introspector.decapitalize(serviceInterface.substring(serviceInterface.lastIndexOf(".") + 1));
//        }
//
//        AbstractBeanDefinition beanDefinition = gatewayProxyBuilder.getBeanDefinition();
//
//        return new BeanDefinitionHolder(beanDefinition, id);
//    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }



    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}
